package com.onpositive.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NumberProbabilityProvider extends AbstractValidityProvider<Number> {
	
//	private static class CustomComparator implements Comparator<Double>
//	{		
//		private static final double epsilon = 2*Double.MIN_VALUE ;
//		@Override
//		public int compare(Number arg0, Number arg1) {
//			
//			double diff = arg0.doubleValue() - arg1.doubleValue() ;
//			int sgn = diff > 0 ? 1 : -1 ;
//			diff *= sgn ;
//			diff = diff < epsilon ? 0 : diff ;
//			sgn = diff != 0 ? 0 : sgn ;
//			int iDiff = (int)( diff + 1.5 ) ;  			
//
//			return sgn * iDiff;
//		}
//		
//	}

	private static final double epsilon = 0.0000001 ;
	private ArrayList<Double> elements ;
	private ArrayList<Double> probabilities ;
	public int N ;
	
	public NumberProbabilityProvider(Iterable<Number> array) {
		super(array);
		
		ArrayList<Double> list = new ArrayList<Double>() ;
		
		for( Number n : array )
			if( n != null )
				list.add( n.doubleValue() ) ;
				
		init(list);						
	}

	private void init( List<Double> list) {
		N = list.size() ;
				
		if( N < 2 )
		{
			return ;
		}
	
		list.add( Double.NEGATIVE_INFINITY );
		list.add( Double.POSITIVE_INFINITY );
		
//		CustomComparator customComparator = new CustomComparator() ;
		Collections.sort( list ) ;
		
		
		list.set(  0 , 2*list.get(1) - list.get( 2 ) ) ;
		list.set( N+1, 2*list.get(N) - list.get(N-1) ) ;
		
		ArrayList<Double>  listTmp = new ArrayList<Double>( list.size() ) ;
		ArrayList<Integer> pCount  = new ArrayList<Integer>( list.size() ) ;
		double prev = list.get(0)  ;
		listTmp.add(prev) ;
		pCount.add(0) ;
		for( double d : list )
		{
			if( Math.abs(prev-d) > epsilon )
			{
				listTmp.add(d) ;
				pCount.add(1) ;
				prev = d ;
			}
			else
				pCount.set( pCount.size()-1, pCount.get( pCount.size()-1) + 1 ) ;
			
		}
		
		N = listTmp.size()-2 ;
		if( N < 2 )
			return ;
		
		this.elements = new ArrayList<Double>( listTmp.subList(1, N+1) ) ;
		
		double h = 2.0/N ;
		double minStep = 0 ;
		this.probabilities = new ArrayList<Double>( listTmp.size() ) ;
		for( int i = 0 ; i < N ; i++ )
		{
			double p1 = listTmp.get(i  ) ;
			double p2 = listTmp.get(i+1) ;
			double p3 = listTmp.get(i+2) ;
			
			double l = p3-p1 ;
			double _l = p2-p1 ;
			minStep = _l > epsilon ? ( minStep < _l ? minStep : _l ) : minStep ;
			
			double p = l > epsilon ? h/l : probabilities.get(probabilities.size()-1) ;
			
						
			probabilities.add( ( pCount.get(i+1)*h)/l ) ;
		}
	}

	@Override
	public Boolean getValidity(Number var) {
		// TODO Auto-generated method stub
		return null;
	}

	public ArrayList<Double> getProbabilities() {
		return probabilities;
	}

	public ArrayList<Double> getElements() {
		return elements;
	}


}
